package taillog

import (
	"fmt"
	"github.com/hpcloud/tail"
	"logagent/register"
	"logagent/utils"
	"sync"
	"time"
)

type CollectConf struct {
	Filename string `json:"filename"`
	Key      string `json:"key"`
}

type TailObj struct {
	tail     *tail.Tail
	conf     *CollectConf
	exitChan chan struct{}
	status   int
}

type Message struct {
	Timestamp time.Time `json:"timestamp"`
	Msg       string    `json:"msg"`
	Pos       int64     `json:"pos"`
	Key       string    `json:"key,omitempty"`
	File      string    `json:"file"`
}

type TailObjMgr struct {
	wg       sync.WaitGroup
	tailsObj []*TailObj
	msgChan  chan *Message
}

type FileStat struct {
	Inode    uint64
	offset   int
	FilePath string
}

type FileStatMgr struct {
	filestats []*FileStat
	rwlock    sync.RWMutex
}

func (mgr *TailObjMgr) GetChannel() chan *Message {
	return mgr.msgChan
}

func (mgr *TailObjMgr) Close() {
	for _, obj := range mgr.tailsObj {
		obj.exitChan <- struct{}{}
	}
	mgr.wg.Wait()
}

func InitTail(conf []*CollectConf, chanSize int) (mgr *TailObjMgr, err error) {
	if len(conf) == 0 {
		err = fmt.Errorf("无效的conf :%v", conf)
		return
	}
	t := &TailObjMgr{
		msgChan: make(chan *Message, chanSize),
	}
	t.createTasks(conf)
	t.readFromTail()
	return t, nil
}

func (mgr *TailObjMgr) createTasks(conf []*CollectConf) {
	for _, v := range conf {
		mgr.createTask(v)
	}
}

func (mgr *TailObjMgr) createTask(conf *CollectConf) {
	location := &tail.SeekInfo{Offset: 0, Whence: 0}
	if record, ok := register.Reg.Mreg[conf.Filename]; ok {
		location.Offset = record.Pos
	}
	tail_obj, err := tail.TailFile(conf.Filename, tail.Config{
		Location:  location,
		ReOpen:    true,
		Follow:    true,
		MustExist: false,
		Poll:      true,
	})
	if err != nil {
		utils.Fatalf("tail 操作文件错误:", err)
	}
	obj := &TailObj{
		tail:     tail_obj,
		conf:     conf,
		exitChan: make(chan struct{}),
	}

	mgr.tailsObj = append(mgr.tailsObj, obj)
}

func (mgr *TailObjMgr) readFromTail() {
	for _, obj := range mgr.tailsObj {
		mgr.wg.Add(1)
		go func(obj *TailObj) {
			defer mgr.wg.Done()
			for true {
				select {
				case msg, ok := <-obj.tail.Lines:
					if !ok {
						utils.Println("Tail file close reopen, filename: ", obj.tail.Filename)
						time.Sleep(100 * time.Millisecond)
						continue
					}
					fmt.Println(msg)
					line := &Message{
						Timestamp: msg.Time,
						Key:       obj.conf.Key,
						Msg:       msg.Text,
						Pos:       msg.Pos,
						File:      obj.tail.Filename,
					}
					mgr.msgChan <- line
				case <-obj.exitChan:
					goto END
				}
			}
		END:
			return
		}(obj)
	}

}
